Separation Criteria for sSFR vs \(M_\star\)

This code contains an example of the fitting and visualization tools used in the Master Thesis: “Characterization of nuclear activity for galaxies in different large-scale environments in terms of morphology, colour, and specific star formation rate” by Daniel Ariza Quintana.

[1]:
import imageio
import numpy as np
import pandas as pd
import plotly.graph_objects as go

from SliceFit import *
from glob import glob

Data

[2]:
## SUPER TABLA ##
T    = pd.read_csv('../Data/Supertabla/Supertabla_A.csv', dtype={'objID':str}) # Todas las galaxias

# Data with conditions
c    = (T.logSFR>-10)&(T['logM*']>-10)&(T.Z < 0.1077) # Setting cut in Z for SDSS bias
M    = T[c]['logM*'].to_numpy()     # Mass
SF   = T[c]['log(sSFR)'].to_numpy() # Specific Star Forming Rate

Example

Here we show an example of how the Slice Fit works, and how to use it. It is done for the sSFR vs stellar mass diagram on a logarithmic scale. We make use of the bimodality in the diagram to perform the linear fit separating galaxy populations.

[11]:
# Interactive display of the binodality of the diagram with Plotly
X, Y, Z = contour_params_array(M, SF, Nbins=50)

# Create surface plot
fig = go.Figure(
      data=[go.Surface(z=Z, x=X, y=Y, colorscale='Viridis', cmin=10, cmax=1400,
            colorbar=dict(len=0.8, thickness=15, yanchor="middle"))],
      layout={'height':700, 'width':600}
                )

# Customize layout
fig.update_layout(title=r'Bimodality of the sSFR vs stellar mass diagram',
                  title_font=dict(size=24),
                  scene=dict(zaxis_title='Counts', xaxis_title=r'log (M*/Ms)',
                             yaxis_title='log(sSFR/yr-1)')
                 )

# Show plot
fig.show()
[4]:
# Obtaining the fits for the sSFR vs stellar mass diagram
Nb = 50
Fits = Contour_Fit_sig(M, SF)
/Users/daniarizaq/Desktop/FisyMat/TFM/code/Example/SliceFit.py:103: RuntimeWarning:

Number of calls to function has reached maxfev = 1400.

[5]:
# Plotting the fit
plot_Contour_Fit(M, SF, Fits, 'Example', cmin=10, nc=15, hw=0.11)
50it [00:06,  7.65it/s]
[6]:
# To visualize we make a gif
im_names = glob('./Example/*')  # Image names
im_names.sort()                 # Sort images
gims = []
for n in im_names:
    gims.append(imageio.imread(n))  # Load imgs

imageio.mimsave('./SliceFit.gif', gims, 'GIF', fps=5, loop=20) # Create gif
/var/folders/ct/pvdxd6m17rz14sps5rwm3vtw0000gn/T/ipykernel_4904/1925795393.py:6: DeprecationWarning:

Starting with ImageIO v3 the behavior of this function will switch to that of iio.v3.imread. To keep the current behavior (and make this warning disappear) use `import imageio.v2 as imageio` or call `imageio.v2.imread` directly.

f3d41cf0b30e4377ab538c46a7a513b7

Now that we have a double gaussian for every slice we are able to find the minimums.

[7]:
## Finding the minimums between pekas
val = Valley(Fits, M, SF, -14, -8)
_images/ExampleSliceFit_11_0.png

We can see there are many points out of the bimodal zone, so we must constrain the valley points before the linear regresion.

[8]:
# Constraining the minimums and fitting.
def f(x,a,b):
    return a*x+b
x = val[25:43,0]
y = val[25:43,1]

line, corr = curve_fit(f, x, y)
a, b = line
line = np.array(line)

print(f'a = {a:.4f} +- {corr[0][0]:.4f}')
print(f'b = {b:.4f} +- {corr[1][1]:.4f}')



r = np.linspace(np.min(x), np.max(x))
plt.plot(r, a*r+b, label=f'{a:.3f}x + {b:.3f}')
plt.scatter(x,y)
plt.legend()
a = -0.6961 +- 0.0007
b = -3.8316 +- 0.0851
[8]:
<matplotlib.legend.Legend at 0x16b0d2a90>
_images/ExampleSliceFit_13_2.png
[9]:
plot_cont(M,SF,nc=10, scat=val[25:40], linear=line, err=3*corr[1][1])
_images/ExampleSliceFit_14_0.png

We arrive to the final fit, which serves as separation criteria for properties, in this case SFR.